package com.dx.mes.common.core.dao.impl;

import com.dx.mes.common.bean.entity.UUIDObject;
import com.dx.mes.common.core.dao.GenericHisDao;
import com.dx.mes.common.core.redis.RedisManager;
import com.dx.mes.common.transcoder.util.AppContext;
import com.dx.mes.common.transcoder.util.GUIDGenerator;
import com.dx.mes.common.transcoder.util.LocalUtil;
import com.dx.mes.common.transcoder.util.Util;
import org.apache.log4j.Logger;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

//import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

//import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

@Repository
public class GenericHibernateHisDao<T extends Serializable, PK extends Serializable> extends HibernateDaoSupport
        implements GenericHisDao<T, PK> {
    private static final Logger logger = Logger.getLogger(RedisManager.class);

    private Class<T> entityClass;

    @Resource
    public void setSessionFactoryOverride(SessionFactory sessionFactoryHis) {
        super.setSessionFactory(sessionFactoryHis);
    }

    public GenericHibernateHisDao() {
        this.entityClass = null;
        Class c = getClass();
        Type t = c.getGenericSuperclass();
        if (t instanceof ParameterizedType) {
            Type[] p = ((ParameterizedType) t).getActualTypeArguments();
            this.entityClass = (Class<T>) p[0];
        }
    }


    public T get(PK id) {
        if (id == null) {
            return null;
        }
        return (T) getHibernateTemplate().get(entityClass, id);
    }

    public T getWithLock(PK id, LockMode lock) {
        if (id == null) {
            return null;
        }
        T t = (T) getHibernateTemplate().get(entityClass, id, lock);
        if (t != null) {
            this.flush(); // 立即刷新，否则锁不会生效。
        }
        return t;
    }

    public T load(PK id) {
        return (T) getHibernateTemplate().load(entityClass, id);
    }

    public T loadWithLock(PK id, LockMode lock) {
        T t = (T) getHibernateTemplate().load(entityClass, id, lock);
        if (t != null) {
            this.flush(); // 立即刷新，否则锁不会生效。
        }
        return t;
    }

    public List<T> loadAll() {
        return (List<T>) getHibernateTemplate().loadAll(entityClass);
    }

    private void setEntityCommonProperty(T entity, String operation) {
        ((UUIDObject) entity).setPv_unq_seq_id(((UUIDObject) entity).getUnq_seq_id());
        ((UUIDObject) entity).setUnq_seq_id(GUIDGenerator.javaGUID());
        ((UUIDObject) entity).setOperation(operation);
        ((UUIDObject) entity).setOpe_tbl_name(entity.getClass().getSimpleName().toUpperCase());
        ((UUIDObject) entity).setSta_time_d(Util.getDoubleTime());
        ((UUIDObject) entity).setOpe_evt_name(AppContext.getCurrServiceName());
        ((UUIDObject) entity).setOpe_evt_node(LocalUtil.getLocalInfo().getIp());
        ((UUIDObject) entity).setOpe_evt_usr(LocalUtil.getLocalInfo().getHostName());
        ((UUIDObject) entity).setOpe_evt_no(AppContext.getCurrEventNumber());
    }

    private void setEntityCommonPropertyNew(Collection<T> entities, String operation) {
        for (T entity : entities) {
            ((UUIDObject) entity).setPv_unq_seq_id(((UUIDObject) entity).getUnq_seq_id());
            ((UUIDObject) entity).setUnq_seq_id(GUIDGenerator.javaGUID());
            ((UUIDObject) entity).setOperation(operation);
            ((UUIDObject) entity).setOpe_tbl_name(entity.getClass().getSimpleName().toUpperCase());
            ((UUIDObject) entity).setSta_time_d(Util.getDoubleTime());
            ((UUIDObject) entity).setOpe_evt_name(AppContext.getCurrServiceName());
            ((UUIDObject) entity).setOpe_evt_node(LocalUtil.getLocalInfo().getIp());
            ((UUIDObject) entity).setOpe_evt_usr(LocalUtil.getLocalInfo().getHostName());
            ((UUIDObject) entity).setOpe_evt_no(AppContext.getCurrEventNumber());
        }

    }

    public List<T> find(String queryString) {
//        return getHibernateTemplate().find(queryString);
        final List<?> objects = getHibernateTemplate().find(queryString);
        return objects.stream().map(o->(T)o).collect(Collectors.toList());
    }

    @SuppressWarnings("rawtypes")
    public List<T> find(String queryString, Object values) {
        return getHibernateTemplate().find(queryString, values).stream().map(o->(T)o).collect(Collectors.toList());
    }

    @SuppressWarnings("rawtypes")
    public List find(String queryString, Object[] values) {
        return getHibernateTemplate().find(queryString, values);
    }


    public void lock(T entity, LockMode lock) {
        getHibernateTemplate().lock(entity, lock);
    }

    public void flush() {
        getHibernateTemplate().flush();
    }

    public List listBySQL(String sql) {
        Session session = getCrSession();
        return session.createSQLQuery(sql).list();
    }

    public List findBySQL(String sql) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createSQLQuery(sql);
        return q.list();
    }

    @SuppressWarnings("unchecked")
    public List<T> findBySQL(String sql, Class clazz) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createSQLQuery(sql).addEntity(clazz);
        return q.list();
    }

    @SuppressWarnings("unchecked")
    public List<T> findBySQL(String sql, Class clazz, Object... args) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createSQLQuery(sql).addEntity(clazz);
        return q.list();
    }

    public T findBySQLOnly(String sql) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createSQLQuery(sql);
        return (T) q.uniqueResult();
    }

    public List<String> findDistStringList(final String strSql) {
        Query query = getCrSession().createQuery(strSql);
        return query.list();
    }

    public T comTblRead(String sql) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createQuery(sql);
        Object obj = q.uniqueResult();
        return (T) obj;
    }

    public T comTblReadLock(String sql, String tbl_name) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createQuery(sql);
        q.setLockMode(tbl_name, LockMode.READ);
        Object obj = q.uniqueResult();
        return (T) obj;
    }

    public List comTblRead2nd(String sql) {
        Session s = this.getHibernateTemplate().getSessionFactory().getCurrentSession();
        Query q = s.createQuery(sql);
        return q.list();
    }

    public T findOnlyOne(String queryString, Object[] values) {
        return ((List<T>) getHibernateTemplate().find(queryString, values)).get(0);
    }

    public Session getCrSession() {
        return getHibernateTemplate().getSessionFactory().getCurrentSession();
    }

    public void flushCurSession() {
        Session curSession = this.getCrSession();
        curSession.flush();
    }

    public long getCountBySql(String sql) {
        return (Long) getHibernateTemplate().iterate(sql).next();
    }

    @SuppressWarnings("unchecked")
    public List<T> list(String hql, Object... values) {
        Query query = this.createQuery(hql, values);
        return query.list();
    }

    @SuppressWarnings("unchecked")
    public T uniqueResult(String hql, Object... values) {
        Query query = this.createQuery(hql, values);
        return (T) query.uniqueResult();
    }

    protected Query createQuery(String hql, Object... values) {
        Query query = getCrSession().createQuery(hql);

        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i, values[i]);
            }
        }
        return query;
    }

    @SuppressWarnings("unchecked")
    public List<T> listWithLock(String hql, Object... values) {
        Session session = this.getCrSession();
        Query query = this.createQuery(hql, values);
        List<T> ts = query.list();
        for (T t : ts) {
            session.lock(t, LockMode.UPGRADE);
        }
        return ts;
    }

    @SuppressWarnings("unchecked")
    public T uniqueResultWithLock(String hql, Object... values) {
        Session session = this.getCrSession();
        Query query = this.createQuery(hql, values);
        T t = (T) query.uniqueResult();
        if (t == null) {
            return t;
        }
        session.lock(t, LockMode.UPGRADE);
        return t;
    }
}
